package org.xmeta;

/**
 * <p>ContextVarProvider通常只针对动作，而不针对模型的行为。目的是提供资源，以及自动管理资源等。比如提供数据库连接，并在执行完毕后自动释放连接。</p>
 *
 * <p>通常在init方法里初始化资源，并放到动作上下文的当前栈中。在onSuccess和onException中释放资源，如执行close方法。</p>
 *
 * <p>资源复用。目前资源复用采用资源id判断法，即如果资源的id相同那么认为是同一个资源。比如判断一个数据库连接是否已经存在，可以使用Object findPreContextVar(String id, ActionListenerExecutor executor)
 * 方法获取同id的资源是否已经存在。资源是否复用，是由资源自己觉得。</p>
 *
 * <p>默认一个ContextVarProvider只提供一个资源，如果有多个资源，且资源是可以复用的，那么需要重写Object getContextVarById(String id)方法。</p>
 */
public abstract class ContextVarProvider implements ActionListener{
    /**
     * 查找是否之前的ContextProvider已经提供了相同id的变量了。比如同一个数据源应该只需要设置一次，不用重复获取。
     *
     * @param id 变量的ID
     * @param executor 动作监听的执行器
     * @return 如果存在返回该变量，否则返回Null
     */
    public Object findPreContextVar(String id, ActionListenerExecutor executor) {
        for (int i=0; i<executor.getCurrentIndex(); i++) {
            ActionListener listener = executor.getActionListener(i);
            if (listener instanceof ContextVarProvider) {
                ContextVarProvider provider = (ContextVarProvider) listener;
                Object var = provider.getContextVarById(id);
                if (var != null) {
                    return var;
                }
            }
        }

        return null;
    }

    /**
     * 如果本ContextVarProvider提供指定id的资源，那么返回该对象。
     *
     * @param id 资源id
     * @return 资源对象，如果存在
     */
    public Object getContextVarById(String id) {
        String varId = getId();
        if (varId != null && !varId.isEmpty() && varId.equalsIgnoreCase(id)) {
            return getVar();
        }

        return null;
    }

    /**
     * 返回资源id。适合单资源时，多资源应该重写getContextVarById方法
     * 。
     * @return 资源id
     */
    public abstract String getId();

    /**
     * 返回资源对象。适合单资源时，多资源应该重写getContextVarById方法
     * 。
     * @return 资源对象
     */
    public abstract Object getVar();
}
